#include "fd_manager.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include "hook.h"

namespace sylar
{

FdCtx::FdCtx(int fd) 
    : m_isInit(false)
    , m_isSocket(false)
    , m_isSysNoBlock(false)
    , m_isUserNoBlock(false)
    , m_isClosed(false)
    , m_fd (fd) 
    , m_recvTimeout(0)
    , m_sendTimeout(0)
    , m_iomanger(nullptr)
{
    init();
}

FdCtx::~FdCtx()
{
}

bool FdCtx::init()
{
    if (m_isInit)
    {
        return true;
    }

    m_recvTimeout = -1;
    m_sendTimeout = -1;

    struct stat fd_stat;

    if (-1 == fstat(m_fd, &fd_stat))
    {
        m_isInit = false;
        m_isSocket = false;
    }
    else
    {
        m_isInit = true;
        m_isSocket = S_ISSOCK(fd_stat.st_mode);
    }

    if (m_isSocket)
    {
        int flag = fcntl_f(m_fd, F_GETFD, 0);
        if (! (flag & O_NONBLOCK))
        {
            fcntl_f(m_fd, F_SETFD, flag | O_NONBLOCK);
        }
        m_isSysNoBlock = true;
    }
    else
    {
        m_isSysNoBlock = false;
    }

    m_isUserNoBlock = false;
    m_isClosed = false;
    return m_isInit;
}

/// @brief 设置句柄的超时事件
/// @param type 
/// @param v 
void FdCtx::setTimeOut(int type, uint64_t v)
{
    if (type == SO_RCVTIMEO)
    {
        m_recvTimeout = v;
    }
    else
    {
        m_sendTimeout = v;
    }

}

uint64_t FdCtx::getTimeOut(int type)
{
    if (type == SO_RCVTIMEO)
    {
        return m_recvTimeout;
    }
    else
    {
        return m_sendTimeout;
    }
}

FdManager::FdManager()
{
    m_datas.resize(64);
}

/// @brief 删除fd
/// @param fd 
void FdManager::del(int fd)
{
    RWMutexType::WriteLock wlock(m_mutex);
    if(m_datas.size() <= (size_t)fd)
    {
        return;
    }
    m_datas[fd].reset();
}

/// @brief 获取fd的fdctx
/// @param fd 
/// @param auto_create 是否创建新的 
/// @return 
FdCtx::ptr FdManager::get(int fd, bool auto_create)
{
    RWMutexType::ReadLock lock(m_mutex);

    if (m_datas.size() <= (size_t)fd)
    {
        if (auto_create == false)
        {
            return nullptr;
        }
    }
    else
    {
        if (m_datas[fd] || !auto_create)
        {
            return m_datas[fd];
        }
    }
    lock.unlock();

    RWMutexType::WriteLock wlock(m_mutex);
    FdCtx::ptr ctx(new FdCtx(fd));
    m_datas[fd] = ctx;
    return ctx;
}

}